#include "include.h"
#include "grav_system.h"
#include "class_motion_object.h"

void grav_system::calculate_tick(double tick_size) {
	double distance, force;
	vec_3d acc(0, 0, 0);

	///////////////////////refresh small objects/////////////////////
	calculate_distances(grav_objects, small_objects);

	for (int planet_counter = 0; planet_counter < small_objects.size(); planet_counter++) {
		for (int force_counter = 0; force_counter < grav_objects.size(); force_counter++) {
			if (force_counter == planet_counter) continue;
			distance = distances[planet_counter][force_counter];
			force = grav_const*grav_objects[force_counter].get_mass() / pow(distance, 3);

			acc = acc + (grav_objects[force_counter].position - small_objects[planet_counter].position)*force;
		}
		small_objects[planet_counter].vel = small_objects[planet_counter].vel + acc*tick_size;
		small_objects[planet_counter].position = small_objects[planet_counter].position + small_objects[planet_counter].vel*tick_size;

		acc = vec_3d(0, 0, 0);
	}
	//////////////////////////////////////////////////////////////////////

	////////////////////refresh grav objects/////////////////////////////
	calculate_distances(grav_objects, grav_objects);

	for (int planet_counter = 0; planet_counter < grav_objects.size(); planet_counter++) {
		for (int force_counter = 0; force_counter < grav_objects.size(); force_counter++) {
			if (force_counter == planet_counter) continue;
			distance = distances[planet_counter][force_counter];
			force = grav_const*grav_objects[force_counter].get_mass() / pow(distance, 3);

			acc = acc + (grav_objects[force_counter].position - grav_objects[planet_counter].position)*force;
		}
		grav_objects[planet_counter].vel = grav_objects[planet_counter].vel + acc*tick_size;
		grav_objects[planet_counter].position = grav_objects[planet_counter].position + grav_objects[planet_counter].vel*tick_size;

		acc = vec_3d(0, 0, 0);
	}
	///////////////////////////////////////////////////////////////////////
}

void grav_system::calculate_distances(std::vector<motion_object> distance_to, std::vector<motion_object> distance_from) {
	distances = std::vector<std::vector<double>>(distance_from.size(), std::vector<double>(distance_to.size(), 0));

	for (int i = 0; i < distance_from.size(); i++) {
		for (int j = 0; j < distance_to.size(); j++) {
			if (distances[i][j] != 0) distances[i][j] = distances[j][i];
			else distances[i][j] = sqrt(pow(distance_from[i].position.x - distance_to[j].position.x, 2) + pow(distance_from[i].position.y - distance_to[j].position.y, 2) + (distance_from[i].position.z - distance_to[j].position.z, 2));
		}
	}
}

grav_system::grav_system(std::vector<int> grav_objects_id, std::vector<int> small_objects_id, int date_id) {
	populate_system(grav_objects_id, small_objects_id, date_id);
}

void grav_system::populate_system(std::vector<int> grav_objects_id, std::vector<int> small_objects_id, int date_id) {
	grav_objects.resize(grav_objects_id.size() + 1);
	small_objects.resize(small_objects_id.size()); 
	grav_objects[0] = motion_object(1, 0, 0, 0, 0, 0, 0);


	sql::Driver *driver;
	sql::Connection *con;
	sql::Statement *statement;
	sql::ResultSet *res;
	std::stringstream query;
	int i = 0;
	double mass_temp, initx_temp, inity_temp, initz_temp, init_velx_temp, init_vely_temp, init_velz_temp;

	try {
		driver = get_driver_instance();
		con = driver->connect("tcp://192.168.2.103:3306", "Edmund", "fuckit");
		statement = con->createStatement();
		statement->execute("USE solar_system");
		do {
			std::cout << i << std::endl;
			query << "SELECT planet_mass FROM planets WHERE PLANET_ID=" << grav_objects_id[i];
			statement->execute(query.str().c_str());
			res = statement->getResultSet();
			query.str(std::string());

			while (res->next()) {
				mass_temp = res->getDouble(1);
				std::cout << "mass " << mass_temp << std::endl;
			}

			query << "SELECT pos_x, pos_y, pos_z FROM position WHERE PLANET_ID=" << grav_objects_id[i] << " AND DATE_ID=" << date_id;
			statement->execute(query.str().c_str());
			res = statement->getResultSet();
			query.str(std::string());
			while (res->next()) {
				initx_temp = res->getDouble(1);
				inity_temp = res->getDouble(2);
				initz_temp = res->getDouble(3);
				std::cout << "init pos " << initx_temp << " " << inity_temp << " " << initz_temp << std::endl;
			}

			query << "SELECT vel_x, vel_y, vel_z FROM velocity WHERE PLANET_ID=" << grav_objects_id[i] << " AND DATE_ID=" << date_id;
			statement->execute(query.str().c_str());
			res = statement->getResultSet();
			query.str(std::string());
			while (res->next()) {
				init_velx_temp = res->getDouble(1);
				init_vely_temp = res->getDouble(2);
				init_velz_temp = res->getDouble(3);
				std::cout << "init vel " << init_velx_temp << " " << init_vely_temp << " " << init_velz_temp << std::endl;
			}

			grav_objects[i + 1] = motion_object(mass_temp, initx_temp, inity_temp, initz_temp, init_velx_temp, init_vely_temp, init_velz_temp); 
			i++;
		} while (i < grav_objects_id.size());


		i = 0; 
		do {
			std::cout << i << std::endl;
			query << "SELECT planet_mass FROM planets WHERE PLANET_ID=" << small_objects_id[i];
			statement->execute(query.str().c_str());
			res = statement->getResultSet();
			query.str(std::string());

			while (res->next()) {
				mass_temp = res->getDouble(1);
				std::cout << "mass " << mass_temp << std::endl;
			}

			query << "SELECT pos_x, pos_y, pos_z FROM position WHERE PLANET_ID=" << small_objects_id[i] << " AND DATE_ID=" << date_id;
			statement->execute(query.str().c_str());
			res = statement->getResultSet();
			query.str(std::string());
			while (res->next()) {
				initx_temp = res->getDouble(1);
				inity_temp = res->getDouble(2);
				initz_temp = res->getDouble(3);
				std::cout << "init pos " << initx_temp << " " << inity_temp << " " << initz_temp << std::endl;
			}

			query << "SELECT vel_x, vel_y, vel_z FROM velocity WHERE PLANET_ID=" << small_objects_id[i] << " AND DATE_ID=" << date_id;
			statement->execute(query.str().c_str());
			res = statement->getResultSet();
			query.str(std::string());
			while (res->next()) {
				init_velx_temp = res->getDouble(1);
				init_vely_temp = res->getDouble(2);
				init_velz_temp = res->getDouble(3);
				std::cout << "init vel " << init_velx_temp << " " << init_vely_temp << " " << init_velz_temp << std::endl;
			}

			small_objects[i] = motion_object(mass_temp, initx_temp, inity_temp, initz_temp, init_velx_temp, init_vely_temp, init_velz_temp);
			i++;
		} while (i < small_objects_id.size());


		delete res;
		delete statement;
		delete con;
	}
	catch (sql::SQLException &e) {
		std::cout << "something wrong with SQL Server" << std::endl;
	}



}

const double grav_system::grav_const = 39.48;

